package MovieFinderApp.MCGUI;

import javax.swing.*;

import java.awt.*;
import java.awt.event.ActionListener;
import java.beans.EventHandler;
import java.beans.PropertyChangeEvent;
import java.util.Map;
import java.util.Set;
import java.util.Vector;

import MovieFinderApp.MCGUIInterfaces.*;
import MovieFinderApp.LCMovieInterfaces.*;
import MovieFinderApp.MCMovieFinderInterfaces.*;
import MovieFinderApp.MCMovieListerInterfaces.*;

public class GUI extends JFrame implements IGUI, ICustomizeGUI{
    
    private static final long serialVersionUID = 1L;
    
    private int frameWidth = 520;
    private int frameHeight = 200;
    private int distBoxToButt = 40;
    private int distTextFieldToButt = 10;
    private int distPathFieldToButt = 20;
    private int componentsHeight = 24;
    private int distToLeftBorder = 40;
    private int listHeight = 200;
    
    private JLabel pathLabel = new JLabel();
    private JLabel movieFinderLabel = new JLabel();
    private JLabel directorLabel = new JLabel();
    private JComboBox cbox = new JComboBox();
    private JButton findButton = new JButton();
    private JButton changePathButton = new JButton();
    private JTextField directorField = new JTextField();
    private JTextField pathField = new JTextField();
    private JList movieList = new JList();
    
    private IMovieLister movieLister = null;
    private Map<String, IMovieFinder> movieFinders = null;

    public GUI(){
        //get current screen information
        int screenWidth = Toolkit.getDefaultToolkit().getScreenSize().width;
        int screenHeight = Toolkit.getDefaultToolkit().getScreenSize().height;
        
        //set some properties for this frame
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.getContentPane().setLayout(null);
        this.setTitle("MovieFinderApp");
        this.setResizable(false);
        //frame will be located in the middle of the screen at startup
        this.setLocation((screenWidth-this.frameWidth)/2, (screenHeight-this.frameHeight)/2);
        
        //label for path of file containing movies
        this.pathLabel.setText("Choose a file which contains directors and their movies:");
        this.pathLabel.setSize(320, this.componentsHeight);
        this.pathLabel.setLocation(this.distToLeftBorder, 10);
        this.add(this.pathLabel);
        
        //text field for showing path of file containing movies
        this.pathField.setSize(320, this.componentsHeight);
        this.pathField.setLocation(this.pathLabel.getLocation().x, this.pathLabel.getLocation().y+this.pathLabel.getHeight());
        this.pathField.setEditable(false);
        this.add(this.pathField);
        
        //button for choosing a file containing movies
        this.changePathButton.setSize(100, this.componentsHeight);
        this.changePathButton.setLocation(this.pathField.getLocation().x+this.pathField.getWidth()+this.distPathFieldToButt,this.pathField.getLocation().y);
        this.changePathButton.setText("Change...");
        this.changePathButton.addActionListener(EventHandler.create(ActionListener.class, this, "fileChosen"));
        this.add(this.changePathButton);
        
        //label for choosing movie finder
        this.movieFinderLabel.setText("Choose a movie finder:");
        this.movieFinderLabel.setSize(200, this.componentsHeight);
        this.movieFinderLabel.setLocation(this.distToLeftBorder, this.pathField.getLocation().y+this.pathField.getHeight());
        this.add(this.movieFinderLabel);
        
        //combo box for choosing a movie finder
        this.cbox.setSize(200, this.componentsHeight);
        this.cbox.setLocation(this.distToLeftBorder, this.movieFinderLabel.getLocation().y+this.movieFinderLabel.getHeight());
        this.add(this.cbox);
        
        //label for typing in a director
        this.directorLabel.setText("Type in a director:");
        this.directorLabel.setSize(200, this.componentsHeight);
        this.directorLabel.setLocation(this.cbox.getLocation().x+this.cbox.getWidth()+this.distBoxToButt, this.pathField.getLocation().y+this.pathField.getHeight());
        this.add(this.directorLabel);
        
        //text field for filtering by a director
        this.directorField.setSize(200, this.componentsHeight);
        this.directorField.setLocation(this.cbox.getLocation().x+this.cbox.getWidth()+this.distBoxToButt, this.cbox.getLocation().y);
        this.directorField.addActionListener(EventHandler.create(ActionListener.class, this, "directorConfirmed"));
        this.add(this.directorField);
        
        //button for finding the movies and directors
        this.findButton.setSize(100, this.componentsHeight);
        this.findButton.setLocation(this.cbox.getLocation().x+this.cbox.getWidth()+this.distBoxToButt, this.cbox.getLocation().y+this.directorField.getHeight()+this.distTextFieldToButt);
        this.findButton.setText("Find'em!");
        this.findButton.addActionListener(EventHandler.create(ActionListener.class, this, "movieFinderChosen"));
        this.add(this.findButton);
        
        //list with found movies, initially invisible
        this.movieList.setSize((this.directorField.getLocation().x+this.directorField.getWidth())-this.cbox.getLocation().x, this.listHeight);
        this.movieList.setLocation(this.distToLeftBorder, this.findButton.getLocation().y+this.findButton.getHeight()+this.distTextFieldToButt);
        this.movieList.setVisible(false);
        this.add(this.movieList);
        
        this.pack();
        this.setSize(this.frameWidth, this.frameHeight);
        this.setVisible(true);
    }
    
    @Override
    public void propertyChange(PropertyChangeEvent evt) {
        if(evt.getPropertyName().equals("movieArray")){
            this.printMovies((IMovie[])evt.getNewValue());
        }
    }
    
    @Override
    public void setMovieFinders(Map<String, IMovieFinder> movieFinders){
        this.movieFinders = movieFinders;
        Set<String> keySet = this.movieFinders.keySet();
        for(String key:keySet){
            this.cbox.addItem(key);
        }
        this.validate();
    }
    
    @Override
    public void setMovieLister(IMovieLister movieLister){
        this.movieLister = movieLister;
    }
    
    private void printMovies(IMovie[] movies){
        Vector<String> movs = new Vector<String>();
        for(IMovie movie:movies){
            movs.add(movie.toString());
        }

        this.movieList.setListData(movs.toArray());
        this.movieList.setVisible(true);
        
        this.setSize(this.frameWidth, this.frameHeight+this.listHeight);
        this.validate();
    }
    
    public void movieFinderChosen(){
        //check whether a file with movies and directors is specified
        String path = this.pathField.getText();
        if((path==null) || (path.equals(""))){
            JOptionPane.showMessageDialog(null, "No file with directors and movies chosen.", "Error", JOptionPane.WARNING_MESSAGE);
            return;
        }
        
        //read path of file with directors and movies
        String chosenDirector = this.directorField.getText();
        
        //read selection from combo box and set selected movie finder
        IMovieFinder selectedMovieFinder = this.movieFinders.get(this.cbox.getSelectedItem());
        selectedMovieFinder.setFilename(path);
        this.movieLister.setMovieFinder(selectedMovieFinder);
        this.movieLister.moviesDirectedBy(chosenDirector);
    }
    
    public void fileChosen(){
        JFileChooser chooser = new JFileChooser();
        chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
        chooser.setDialogTitle("Choose a file with directors and movies");
        int retVal = chooser.showOpenDialog(null);
        String path = null;
        if(retVal == JFileChooser.APPROVE_OPTION){
            path = chooser.getSelectedFile().getAbsolutePath();
            this.pathField.setText(path);
        }
        this.validate();
    }
    
    public void directorConfirmed(){
        this.movieFinderChosen();
    }
}
